/*
 * #%L
 * Server
 * %%
 * Copyright (C) 2011 Ractoc.com
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.ractoc.opengamefinder.server.plugins;

import com.ractoc.opengamefinder.api.messages.GetAvatarMessage;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import com.ractoc.opengamefinder.api.messages.LoginMessage;
import com.ractoc.opengamefinder.api.results.MessageResultsErrorCodes;
import com.ractoc.opengamefinder.api.messages.RegisterMessage;
import com.ractoc.opengamefinder.api.results.GetAvatarMessageResult;
import com.ractoc.opengamefinder.api.results.LoginMessageResult;
import com.ractoc.opengamefinder.api.vo.AccountVO;
import com.ractoc.opengamefinder.api.vo.AvatarVO;
import com.ractoc.opengamefinder.dao.AccountDAO;
import com.ractoc.opengamefinder.dao.AvatarDAO;
import com.ractoc.opengamefinder.server.SessionObject;
import com.ractoc.opengamefinder.server.tools.HibernateUtil;
import com.ractoc.opengamefinder.server.translators.TranslatorMap;
import com.ractoc.pffj.api.BasePluginMessageResult;
import com.ractoc.pffj.api.PluginLoaderException;
import com.ractoc.pffj.api.PluginMessage;
import com.ractoc.pffj.api.PluginMessageResultListener;

/**
 * The account plugin handles everything account related. This is also where the
 * database is accessed to load / save account related data.
 * 
 * @author ractoc
 * @version 0.1
 */
public class AccountPlugin extends BaseServerPlugin {

    private static Logger logger = Logger.getLogger(AccountPlugin.class.getName());

    /**
     * Default constructor.
     */
    public AccountPlugin() {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void load() throws PluginLoaderException {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void processServerMessage(final PluginMessage msg, final PluginMessageResultListener listener) {
        BasePluginMessageResult result = null;
        logger.debug("message classe received: " + msg.getClass().getName());
        if (msg instanceof LoginMessage) {
            result = loginAccount(msg);
        } else if (msg instanceof RegisterMessage) {
            result = registerAccount(msg);
            logger.debug("Register errorCode: " + result.getErrorCode());
        } else if (msg instanceof GetAvatarMessage) {
            result = getAvatar(msg);
        }
        listener.receivedResult(result);
    }

    private BasePluginMessageResult loginAccount(final PluginMessage msg) {
        final LoginMessageResult lResult = new LoginMessageResult();
        final LoginMessage lMsg = (LoginMessage) msg;
        logger.info("logging in as " + lMsg.getName());
        if (StringUtils.isEmpty(lMsg.getName())) {
            lResult.setErrorCode(MessageResultsErrorCodes.NO_USERNAME);
        } else if (StringUtils.isEmpty(lMsg.getPassword())) {
            lResult.setErrorCode(MessageResultsErrorCodes.NO_PASSWORD);
        } else {
            lResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
            final Session session = HibernateUtil.getSession();
            final Criteria loginAccount = session.createCriteria(AccountDAO.class);
            loginAccount.add(Restrictions.eq("name", lMsg.getName())).add(
                    Restrictions.eq("password", lMsg.getPassword()));
            final AccountDAO accountDAO = (AccountDAO) loginAccount.uniqueResult();
            if (accountDAO == null) {
                lResult.setErrorCode(MessageResultsErrorCodes.INVALID_USERNAME_OR_PASSWORD);
            } else {
                final AccountVO accountVO = (AccountVO) TranslatorMap.translate(accountDAO);
                logger.debug("adding avatar " + accountDAO.getAvatar().getId() + " to account " + accountVO);
                accountVO.setAvatar((AvatarVO) TranslatorMap.translate(accountDAO.getAvatar()));
                lResult.setAccountVO(accountVO);
                // we also store the player id in the session.
                storeSessionValue(SessionObject.PLAYER_ID, accountVO.getId());
            }
        }
        logger.info("loging result: " + lResult.getErrorCode());
        return lResult;
    }

    private LoginMessageResult registerAccount(final PluginMessage msg) {
        final RegisterMessage rMsg = (RegisterMessage) msg;
        LoginMessageResult result = new LoginMessageResult();
        if (StringUtils.isEmpty(rMsg.getName())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_USERNAME);
        } else if (StringUtils.isEmpty(rMsg.getPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_PASSWORD);
        } else if (StringUtils.isEmpty(rMsg.getRepeatPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_PASSWORD);
        } else if (!rMsg.getPassword().equals(rMsg.getRepeatPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.PASSWORDS_DO_NOT_MATCH);
        } else {
            final Session session = HibernateUtil.getSession();
            final Transaction trans = session.beginTransaction();
            final AccountDAO accountDao = new AccountDAO();
            final AvatarDAO avatarDAO = new AvatarDAO();
            avatarDAO.setContent(rMsg.getAvatarFileContent());
            avatarDAO.setType(rMsg.getAvatarFile().substring(rMsg.getAvatarFile().lastIndexOf(".") + 1, rMsg.getAvatarFile().length()));
            accountDao.setName(rMsg.getName());
            accountDao.setPassword(rMsg.getPassword());
            accountDao.setAvatar(avatarDAO);
            result.setErrorCode(MessageResultsErrorCodes.SUCCESS);
            try {
                session.saveOrUpdate(avatarDAO);
                session.saveOrUpdate(accountDao);
                trans.commit();
                logger.debug("registered account id: " + accountDao.getId());
                // on a succesfull login, we automatically proceed to login.
                LoginMessage lMsg = new LoginMessage();
                lMsg.setName(accountDao.getName());
                lMsg.setPassword(accountDao.getPassword());
                result = (LoginMessageResult) loginAccount(lMsg);
//                result.setAccount((AccountVO) TranslatorMap.translate(accountDao));
//                result.getAccount().setAvatar((AvatarVO) TranslatorMap.translate(avatarDAO));
            } catch (final HibernateException e) {
                logger.error("error storing account info.", e);
                result.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
                trans.rollback();
            } finally {
                session.close();
            }
        }
        return result;
    }

    private BasePluginMessageResult getAvatar(PluginMessage msg) {
        GetAvatarMessageResult gaResult = new GetAvatarMessageResult();
        GetAvatarMessage gaMsg = (GetAvatarMessage) msg;
        AvatarVO avatar = gaMsg.getAvatar();
        Session session = HibernateUtil.getSession();
        Criteria crit = session.createCriteria(AvatarDAO.class);
        crit.add(Restrictions.eq("id", avatar.getId()));
        AvatarDAO avatarDAO = null;
        try {
            avatarDAO = (AvatarDAO) crit.uniqueResult();
        } catch (HibernateException ex) {
            logger.error("unable to load avatar", ex);
        }

        if (avatarDAO != null) {
            gaResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
            gaResult.setAvatar((AvatarVO) TranslatorMap.translate(avatarDAO));
        } else {
            gaResult.setErrorCode(MessageResultsErrorCodes.AVATAR_NOT_FOUND);
            gaResult.setAvatar(null);
        }

        return gaResult;
    }
}
